package com.freemalll.merchant.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.freemalll.merchant.MerchantServiceApplication;
import com.freemalll.merchant.domain.dto.DTOAddress;
import com.freemalll.merchant.domain.dto.DTOInnerUseParseConfig;
import com.freemalll.merchant.domain.dto.DTOInterfaceParams;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.SpringApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;


@Component
@RequiredArgsConstructor
public class AddressUtil {

    private final MongoTemplate mongoTemplate;
    private final InterfaceOperational interfaceOperational;

    public static void main(String[] args) {
        try {
            ApplicationContext context = SpringApplication.run(MerchantServiceApplication.class, args);
            AddressUtil addressUtil = context.getBean(AddressUtil.class);
            long time1 = System.currentTimeMillis();
            //DTOAddress address = addressTrans("都市金牛区解放路1段碧蔓汀8栋1单元1613号");
            DTOAddress address = addressUtil.addressTrans("龙泉驿大面梧桐路9号上东阳光2期18栋3单元12号");
            //DTOAddress address = addressTrans("巴中区回凤巴州大道龙湖花园17栋2单元3层2号");
            long time2 = System.currentTimeMillis();
            System.err.println(time2 - time1);
            System.out.println(address.getOldAddress());
            System.out.println(address.getNewAddress());
            System.out.println(address.showAddressSplit());
            //System.out.println(addressTrans("四川省泸州市一码头滨江路二段十四幢3-3-1、四川省泸州市福集镇创业街334号1幢5-4"));
            //System.out.println(addressTrans("重庆"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 特殊处理字符串,替换不规范的地方
     */
    public String addressSpecialDeal(String address) {
        //去除空格
        String removeChars = " \"“”()（）";
        for (char ch : removeChars.toCharArray()) {
            address = address.replace(ch + "", "");
        }
        //去除地址中特殊符号(只去除开始6位的，不然会导致[重庆市江北区建新北路三支路65号耐德佳苑1单元3-2、2.重庆市渝北区回兴街道宝圣大道466号万科朗润园8栋23-8]这种地址单元号3-2、2变成3-22)
        char[] chars = address.toCharArray();
        for (int i = 0; i < chars.length && i <= 6; i++) {
            char ch = chars[i];
            try {
                Integer.parseInt(ch + "");
                address = address.replaceFirst(ch + "", "");
            } catch (Exception e) {
                //System.out.println(e.getMessage());
            }
            if ("、".equals(ch + "")) {
                address = address.replaceFirst(ch + "", "");
            }
            if (".".equals(ch + "")) {
                address = address.replaceFirst(ch + "", "");
            }
        }
        return address;
    }


    public DTOAddress addressTrans(String address, String... type) throws Exception {
        DTOAddress addObj = new DTOAddress();
        addObj.setOldAddress(address);
        //去除空格
        String removeChars = " \"“”()（）";
        for (char ch : removeChars.toCharArray()) {
            address = address.replace(ch + "", "");
        }
        //去除地址中特殊符号(只去除开始6位的，不然会导致[重庆市江北区建新北路三支路65号耐德佳苑1单元3-2、2.重庆市渝北区回兴街道宝圣大道466号万科朗润园8栋23-8]这种地址单元号3-2、2变成3-22)
        char[] chars = address.toCharArray();
        for (int i = 0; i < chars.length && i <= 6; i++) {
            char ch = chars[i];
            try {
                Integer.parseInt(ch + "");
                address = address.replaceFirst(ch + "", "");
            } catch (Exception e) {
                //System.out.println(e.getMessage());
            }
            if ("、".equals(ch + "")) {
                address = address.replaceFirst(ch + "", "");
            }
            if (".".equals(ch + "")) {
                address = address.replaceFirst(ch + "", "");
            }
        }
        if (address.startsWith("新疆") && !address.startsWith("新疆维吾尔自治区")) {
            address = address.replaceFirst("新疆", "新疆维吾尔自治区");
        } else if (address.startsWith("内蒙古") && !address.startsWith("内蒙古自治区")) {
            address = address.replaceFirst("内蒙古", "内蒙古自治区");
        } else if (address.startsWith("广西") && !address.startsWith("广西壮族自治区")) {
            address = address.replaceFirst("广西省", "广西").replaceFirst("广西", "广西壮族自治区");
        } else if (address.startsWith("宁夏") && !address.startsWith("宁夏回族自治区")) {
            address = address.replaceFirst("宁夏", "宁夏回族自治区");
        } else if (address.startsWith("西藏") && !address.startsWith("西藏自治区")) {
            address = address.replaceFirst("西藏", "西藏自治区");
        }

        //地址解析优化
        if (type != null && type.length > 0 && "1".equals(type[0])) {
            DTOInnerUseParseConfig.AliAddressStandard aliAddressStandard = interfaceOperational.getInnerUserParseConfig().getAliAddressStandard();
            if (aliAddressStandard != null && "1".equals(aliAddressStandard.getQuerySwitch())) {
                DTOInterfaceParams params = new DTOInterfaceParams();
                Map<String, String> map = new HashMap<>();
                map.put("text", address);
                params.setUpt(JSON.toJSONString(map));
                params.setRelationId("");
                params.setSendType(DTOInterfaceParams.aliAddressStandard);
                Result send = interfaceOperational.send(params);
                if (send.getCode() == 200) {
                    String data = (String) send.getData();
                    return JSONObject.parseObject(data, DTOAddress.class);
                }
            }
        }

        addObj.setStreet(address);
        //1.数据库校验
        checkProvince(addObj);
        //1.数据库校验
        checkCity(addObj);
        //1.数据库校验
        checkCounty(addObj);
        addObj.setNewAddress(addObj.toString());
        return addObj;
    }

    /**
     * 检核省/直辖市/自治区
     * 逻辑：获取地址第一个字符在mongoDB中进行模糊匹配，找到匹配的对象
     * 通过匹配的对象找到当前对象对应的datatype=0的标准地址，同时将传入
     * 地址字符串对应的地址部分去除。
     */
    public void checkProvince(DTOAddress addObj) {
        // 1. 入参校验：地址为空直接返回
        if (addObj == null || StringUtils.isBlank(addObj.getStreet())) {
            return;
        }

        try {
            String collectionName = "xyd_province";
            // 2. 获取街道首字符，构建右匹配模糊查询条件（原逻辑：^首字符.*）
            String firstStr = addObj.getStreet().substring(0, 1);
            Pattern rightMatchPattern = Pattern.compile("^" + firstStr + ".*$", Pattern.CASE_INSENSITIVE);

            // 构建查询条件：text字段右匹配首字符
            Query query = new Query(Criteria.where("text").regex(rightMatchPattern));

            // 3. 执行查询：返回所有匹配的省份文档（Map类型，兼容原结构）
            Map<String, Object> matchedProvince = null;
            String tempText = "";
            String tempCode = "";
            boolean match = false;

            // 4. 遍历结果，执行双重地址匹配（原逻辑保留）
            for (Map<String, Object> provinceDoc : mongoTemplate.find(query, Map.class, collectionName)) {
                tempText = (String) provinceDoc.get("text");
                tempCode = (String) provinceDoc.get("code");

                // 匹配规则1：街道以完整省份名称开头（保留原注释的过滤规则）
                if (addObj.getStreet().startsWith(tempText)
                        /*&& !addObj.getStreet().startsWith(tempText+"镇")
                        && !addObj.getStreet().startsWith(tempText+"街")
                        && !addObj.getStreet().startsWith(tempText+"路")
                        && !addObj.getStreet().startsWith(tempText+"湾")
                        && !addObj.getStreet().startsWith(tempText+"村")
                        && !addObj.getStreet().startsWith(tempText+"园")
                        && !addObj.getStreet().startsWith(tempText+"新村")
                        && !addObj.getStreet().startsWith(tempText+"驿")*/) {
                    matchedProvince = provinceDoc;
                    match = true;
                    break; // 匹配到直接跳出循环（原逻辑：找到第一个匹配项即终止）
                }

                // 匹配规则2：街道以省份名称截取首字符后开头（需省份名称长度>1）
                if (tempText.length() > 1 && addObj.getStreet().startsWith(tempText.substring(1))
                        /*&& !addObj.getStreet().startsWith(tempText.substring(1)+"镇")
                        && !addObj.getStreet().startsWith(tempText.substring(1)+"街")
                        && !addObj.getStreet().startsWith(tempText.substring(1)+"路")
                        && !addObj.getStreet().startsWith(tempText.substring(1)+"湾")
                        && !addObj.getStreet().startsWith(tempText.substring(1)+"村")
                        && !addObj.getStreet().startsWith(tempText.substring(1)+"园")
                        && !addObj.getStreet().startsWith(tempText.substring(1)+"新村")
                        && !addObj.getStreet().startsWith(tempText.substring(1)+"驿")*/) {
                    tempText = tempText.substring(1); // 调整匹配的文本（截取首字符后）
                    matchedProvince = provinceDoc;
                    match = true;
                    break; // 匹配到直接跳出循环
                }

                // 重置临时变量（未匹配时清空）
                tempText = "";
                tempCode = "";
            }

            // 5. 匹配成功：查询标准省份地址（datatype=0）并填充信息
            if (match && matchedProvince != null) {
                // 构建标准地址查询条件（code匹配 + datatype=0）
                Query standardQuery = new Query(
                        Criteria.where("code").is(matchedProvince.get("code"))
                                .and("datatype").is("0")
                );
                Map<String, Object> standardProvince = mongoTemplate.findOne(standardQuery, Map.class, collectionName);

                if (standardProvince != null) {
                    // 清洗街道：移除匹配的省份名称（包括调整后的tempText）
                    String cleanedStreet = addObj.getStreet()
                            .replaceFirst((String) standardProvince.get("text"), "")
                            .replaceFirst(tempText, "");
                    addObj.setStreet(cleanedStreet);

                    // 填充省份信息到DTO
                    addObj.setProvince((String) standardProvince.get("text"));
                    addObj.setProviceCode((String) standardProvince.get("code"));
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 市/直辖市区/自治州
     * 逻辑：获取地址第一个字符在mongoDB中进行模糊匹配，找到匹配的对象
     * 通过匹配的对象找到当前对象对应的datatype=0的标准地址，同时将传入
     * 地址字符串对应的地址部分去除。
     */
    public void checkCity(DTOAddress addObj) {
        // 1. 入参校验：地址为空直接返回
        if (addObj == null || StringUtils.isBlank(addObj.getStreet())) {
            return;
        }

        try {
            String collectionName = "xyd_city";
            // 2. 获取街道首字符，构建模糊查询条件
            String firstStr = addObj.getStreet().substring(0, 1);
            Pattern fuzzyPattern = Pattern.compile("^.*" + firstStr + ".*$", Pattern.CASE_INSENSITIVE);

            // 构建查询条件：模糊匹配text + 可选省编码过滤
            Query query = new Query(Criteria.where("text").regex(fuzzyPattern));
            if (!StringUtils.isBlank(addObj.getProviceCode())) {
                query.addCriteria(Criteria.where("pcode").is(addObj.getProviceCode()));
            }

            // 3. 执行查询：返回Map类型（避免创建实体类，兼容原文档结构）
            List<Map> cityList = mongoTemplate.find(query, Map.class, collectionName);

            // 4. 存储匹配结果的集合
            List<String> texts = new ArrayList<>();
            List<String> codes = new ArrayList<>();
            List<String> pcodes = new ArrayList<>();
            boolean match = false;

            // 5. 遍历结果，执行双重地址匹配（原逻辑保留）
            for (Map<String, Object> cityDoc : cityList) {
                // 提取文档中的核心字段
                String text = (String) cityDoc.get("text");
                String code = (String) cityDoc.get("code");
                String pcode = (String) cityDoc.get("pcode");

                // 匹配规则1：街道以完整text开头（保留原注释的过滤规则）
                if (addObj.getStreet().startsWith(text)
                        /*&& !addObj.getStreet().startsWith(text+"镇")
                        && !addObj.getStreet().startsWith(text+"街")
                        && !addObj.getStreet().startsWith(text+"路")
                        && !addObj.getStreet().startsWith(text+"湾")
                        && !addObj.getStreet().startsWith(text+"村")
                        && !addObj.getStreet().startsWith(text+"园")
                        && !addObj.getStreet().startsWith(text+"新村")
                        && !addObj.getStreet().startsWith(text+"驿")*/) {
                    match = true;
                    // 只添加长度一致的匹配项（保证匹配度最高）
                    if (texts.isEmpty() || texts.get(0).length() == text.length()) {
                        texts.add(text);
                        codes.add(code);
                        pcodes.add(pcode);
                    }
                }

                // 匹配规则2：街道以text截取首字符后的值开头（text长度需>2）
                if (text.length() > 2 && addObj.getStreet().startsWith(text.substring(1))
                        /*&& !addObj.getStreet().startsWith(text.substring(1)+"镇")
                        && !addObj.getStreet().startsWith(text.substring(1)+"街")
                        && !addObj.getStreet().startsWith(text.substring(1)+"路")
                        && !addObj.getStreet().startsWith(text.substring(1)+"湾")
                        && !addObj.getStreet().startsWith(text.substring(1)+"村")
                        && !addObj.getStreet().startsWith(text.substring(1)+"园")
                        && !addObj.getStreet().startsWith(text.substring(1)+"新村")
                        && !addObj.getStreet().startsWith(text.substring(1)+"驿")*/) {
                    String adjustedText = text.substring(1);
                    match = true;
                    if (texts.isEmpty() || texts.get(0).length() == adjustedText.length()) {
                        texts.add(adjustedText);
                        codes.add(code);
                        pcodes.add(pcode);
                    }
                }
            }

            // 6. 多结果筛选：优先选择重庆(500000)/四川(510000)/云南(530000)
            String finalText = "";
            String finalCode = "";
            String finalPcode = "";
            if (texts.size() > 1) {
                for (int i = 0; i < pcodes.size(); i++) {
                    String provinceCode = pcodes.get(i);
                    if ("500000".equals(provinceCode)
                            || "510000".equals(provinceCode)
                            || "530000".equals(provinceCode)) {
                        finalText = texts.get(i);
                        finalCode = codes.get(i);
                        finalPcode = provinceCode;
                        break;
                    }
                }
            }

            // 7. 无优先级匹配时，取第一个结果
            if (texts.size() > 0 && StringUtils.isBlank(finalText)) {
                finalText = texts.get(0);
            }
            if (codes.size() > 0 && StringUtils.isBlank(finalCode)) {
                finalCode = codes.get(0);
            }
            if (pcodes.size() > 0 && StringUtils.isBlank(finalPcode)) {
                finalPcode = pcodes.get(0);
            }

            // 8. 匹配成功：填充城市信息+补充省份信息（若缺失）
            if (match && !StringUtils.isBlank(finalCode)) {
                // 查询标准城市地址（datatype=0）
                Query standardQuery = new Query(
                        Criteria.where("code").is(finalCode)
                                .and("datatype").is("0")
                );
                Map<String, Object> standardCity = mongoTemplate.findOne(standardQuery, Map.class, collectionName);

                if (standardCity != null) {
                    // 清洗街道：移除匹配的城市名称
                    String cleanedStreet = addObj.getStreet()
                            .replaceFirst((String) standardCity.get("text"), "");
                    addObj.setStreet(cleanedStreet);

                    // 填充城市信息
                    addObj.setCity((String) standardCity.get("text"));
                    addObj.setCityCode((String) standardCity.get("code"));

                    // 补充省份信息（若省编码为空）
                    if (StringUtils.isBlank(addObj.getProviceCode()) && !StringUtils.isBlank(finalPcode)) {
                        Query provinceQuery = new Query(
                                Criteria.where("code").is(finalPcode)
                                        .and("datatype").is("0")
                        );
                        Map<String, Object> province = mongoTemplate.findOne(provinceQuery, Map.class, "province");
                        if (province != null) {
                            addObj.setProvince((String) province.get("text"));
                            addObj.setProviceCode((String) province.get("code"));
                        }
                    }
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * 县/盟/旗/区
     * 逻辑：获取地址第一个字符在mongoDB中进行模糊匹配，找到匹配的对象
     * 通过匹配的对象找到当前对象对应的datatype=0的标准地址，同时将传入
     * 地址字符串对应的地址部分去除。
     */
    public void checkCounty(DTOAddress addObj) {
        // 校验入参
        if (addObj == null || StringUtils.isBlank(addObj.getStreet())) {
            return;
        }

        String collType = "xyd_county";
        // 获取街道第一个字符
        String firstStr = addObj.getStreet().substring(0, 1);

        // 构建查询条件
        Query query = new Query();
        // 模糊匹配包含第一个字符的记录（不区分大小写）
        Pattern pattern = Pattern.compile("^.*" + firstStr + ".*$", Pattern.CASE_INSENSITIVE);
        query.addCriteria(Criteria.where("text").regex(pattern));

        // 补充省份编码条件（如果存在）
        if (StringUtils.isNotBlank(addObj.getProviceCode())) {
            query.addCriteria(Criteria.where("pcode").is(addObj.getProviceCode()));
        }

        // 补充城市编码条件（如果存在）
        if (StringUtils.isNotBlank(addObj.getCityCode())) {
            query.addCriteria(Criteria.where("ccode").is(addObj.getCityCode()));
        }

        // 执行查询（返回Map类型，避免创建实体类）
        List<Map> cursor = mongoTemplate.find(query, Map.class, collType);

        // 存储查询结果的集合
        List<String> texts = new ArrayList<>();
        List<String> codes = new ArrayList<>();
        List<String> pcodes = new ArrayList<>();
        List<String> ccodes = new ArrayList<>();
        boolean match = false;

        // 遍历查询结果
        for (Map<String, Object> obj : cursor) {
            String text = obj.get("text").toString();
            String code = obj.get("code").toString();
            String pcode = obj.get("pcode").toString();
            String ccode = obj.get("ccode").toString();

            // 地址前缀匹配逻辑（保留原注释的过滤规则）
            if (addObj.getStreet().startsWith(text)
//                && !addObj.getStreet().startsWith(text+"镇")
//                && !addObj.getStreet().startsWith(text+"街")
//                && !addObj.getStreet().startsWith(text+"路")
//                && !addObj.getStreet().startsWith(text+"湾")
//                && !addObj.getStreet().startsWith(text+"村")
//                && !addObj.getStreet().startsWith(text+"园")
//                && !addObj.getStreet().startsWith(text+"新村")
//                && !addObj.getStreet().startsWith(text+"驿")
            ) {
                match = true;
                // 只添加长度相同的匹配项（保持原匹配度逻辑）
                if (texts.isEmpty() || texts.get(0).length() == text.length()) {
                    texts.add(text);
                    codes.add(code);
                    pcodes.add(pcode);
                    ccodes.add(ccode);
                }
            }
        }

        // 处理多结果场景（优先选择重庆/四川/云南）
        String text = "";
        String code = "";
        String pcode = "";
        String ccode = "";

        if (texts.size() > 1) {
            for (int i = 0; i < pcodes.size(); i++) {
                String provinceCode = pcodes.get(i);
                if ("500000".equals(provinceCode) || "510000".equals(provinceCode) || "530000".equals(provinceCode)) {
                    text = texts.get(i);
                    code = codes.get(i);
                    pcode = provinceCode;
                    ccode = ccodes.get(i);
                    break;
                }
            }
        }

        // 设置默认值（取第一个匹配项）
        if (texts.size() > 0 && StringUtils.isBlank(text)) {
            text = texts.get(0);
        }
        if (codes.size() > 0 && StringUtils.isBlank(code)) {
            code = codes.get(0);
        }
        if (pcodes.size() > 0 && StringUtils.isBlank(pcode)) {
            pcode = pcodes.get(0);
        }
        if (ccodes.size() > 0 && StringUtils.isBlank(ccode)) {
            ccode = ccodes.get(0);
        }

        // 填充地址信息（当匹配成功时）
        if (match) {
            // 查询标准县级地址（datatype=0）
            Query standardQuery = new Query();
            standardQuery.addCriteria(Criteria.where("code").is(code))
                    .addCriteria(Criteria.where("datatype").is("0"));
            Map<String, Object> result = mongoTemplate.findOne(standardQuery, Map.class, collType);

            if (result != null) {
                // 处理街道信息（移除匹配的县级名称及后缀）
                String street = addObj.getStreet()
                        .replaceFirst(result.get("text").toString(), "")
                        .replaceFirst(text, "")
                        .replaceFirst("县", "")
                        .replaceFirst("区", "");
                addObj.setStreet(street);

                // 设置县级信息
                addObj.setCounty(result.get("text").toString());
                addObj.setCountyCode(result.get("code").toString());

                // 补充省份信息（如果缺失）
                if (StringUtils.isBlank(addObj.getProviceCode())) {
                    Query provinceQuery = new Query();
                    provinceQuery.addCriteria(Criteria.where("code").is(pcode))
                            .addCriteria(Criteria.where("datatype").is("0"));
                    Map<String, Object> province = mongoTemplate.findOne(provinceQuery, Map.class, "province");
                    if (province != null) {
                        addObj.setProvince(province.get("text").toString());
                        addObj.setProviceCode(province.get("code").toString());
                    }
                }

                // 补充城市信息（如果缺失）
                if (StringUtils.isBlank(addObj.getCityCode())) {
                    Query cityQuery = new Query();
                    cityQuery.addCriteria(Criteria.where("code").is(ccode))
                            .addCriteria(Criteria.where("datatype").is("0"));
                    Map<String, Object> city = mongoTemplate.findOne(cityQuery, Map.class, "city");
                    if (city != null) {
                        addObj.setCity(city.get("text").toString());
                        addObj.setCityCode(city.get("code").toString());
                    }
                }
            }
        }
    }
}
